#include <iostream>
#include <fstream>
#include <string>

#include "Error.h"
#include "Scanner.h"
#include "Parser.h"
#include "Resolver.h"
#include "Interpreter.h"

using namespace std;

Interpreter interpreter{};
string source;

inline string getLine(int line) {
    int cnt = 0;
    string::const_iterator lst=source.cbegin();
    for (auto it=source.cbegin(); it!=source.cend(); it++) {
        //cout<<(lst-source.cbegin())<<" "<<(it-lst)<<" "<<cnt<<'\n';
        if (cnt<line) {
            if ((*it)=='\n') {
                cnt++;
                if (cnt==line) {
                    if (cnt==1)
                        return source.substr(lst-source.cbegin(), it-lst);
                    else //cnt>1
                        return source.substr(lst-source.cbegin()+1, it-lst-1);
                } else {
                    lst=it;
                }
            }
        }
    }
    return "<Somewhere beyond your source input>";
}

void run(string_view source) {
    Scanner scanner {source};
    vector<Token> tokens = scanner.scanTokens();
    Parser parser{tokens};
    vector<shared_ptr<Stmt>> statements = parser.parse();

    //Parsing error;
    if (hadError) return;

    Resolver resolver{interpreter};
    resolver.resolve(statements);

    // Stop if there was a resolution error;
    if (hadError) return;

    interpreter.interpret(statements);
}

void runFile(string_view path) {
    ifstream file{path.data(), ios::in};
    if (!file) {
        cerr<<"Error: Can't open file at \""<<path<<"\".\n";
        exit(74);
    }

    string tmp;
    while (getline(file, tmp)) {
        source+=tmp+'\n';
    }

    run(source);

    //If there's an error, then have a different exit code:
    if (hadRuntimeError) exit(70);
    if (hadError) exit(65);
}

void runPrompt() {
    cout<<"Lox++ 1.0.1 | Running in Prompt mode:"<<endl;
    while (true) {
        cout<<">>> ";
        if (!getline(cin, source)) break;
        source+='\n';
        run(source);
        hadError=false;
        hadRuntimeError=false;
    }
}


int main(int argc, char* argv[]) {
//    AstPrinterTest();
    if (argc>2) {
        cout<<"Usage: loxpp [script]\n";
        exit(64);
    } else if (argc==2) {
        runFile(argv[1]);
    } else {
        runPrompt();
    }
}
